<html><head>
    <title>TextAreaDemo.java</title>
    <link type="text/css" rel="stylesheet" href="demo.css"/>
</head><body>
<ul>
    <li><a href="demo.html">Floating &lt;div&gt; Demo</a></li>
    <li><a href="table.html">Table Demo</a></li>
    <li><a href="list.html">Ordered List Demo</a></li>
    <li>TextAreaDemo.java</li>
</ul>
<pre>
<span class="comment">/*</span>
<span class="comment"> * Copyright (c) 2008-2010, Matthias Mann</span>
<span class="comment"> *</span>
<span class="comment"> * All rights reserved.</span>
<span class="comment"> *</span>
<span class="comment"> * Redistribution and use in source and binary forms, with or without</span>
<span class="comment"> * modification, are permitted provided that the following conditions are met:</span>
<span class="comment"> *</span>
<span class="comment"> *     * Redistributions of source code must retain the above copyright notice,</span>
<span class="comment"> *       this list of conditions and the following disclaimer.</span>
<span class="comment"> *     * Redistributions in binary form must reproduce the above copyright</span>
<span class="comment"> *       notice, this list of conditions and the following disclaimer in the</span>
<span class="comment"> *       documentation and/or other materials provided with the distribution.</span>
<span class="comment"> *     * Neither the name of Matthias Mann nor the names of its contributors may</span>
<span class="comment"> *       be used to endorse or promote products derived from this software</span>
<span class="comment"> *       without specific prior written permission.</span>
<span class="comment"> *</span>
<span class="comment"> * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS</span>
<span class="comment"> * &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT</span>
<span class="comment"> * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR</span>
<span class="comment"> * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR</span>
<span class="comment"> * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,</span>
<span class="comment"> * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,</span>
<span class="comment"> * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR</span>
<span class="comment"> * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF</span>
<span class="comment"> * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING</span>
<span class="comment"> * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS</span>
<span class="comment"> * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</span>
<span class="comment"> */</span>
<span class="keyword-directive">package</span> textarea;

<span class="keyword-directive">import</span> de.matthiasmann.twl.DesktopArea;
<span class="keyword-directive">i</span><span class="keyword-directive">mport</span> de.matthiasmann.twl.Event;
<span class="keyword-directive">import</span> de.matthiasmann.twl.FPSCounter;
<span class="keyword-directive">import</span> de.matthiasmann.twl.GUI;
<span class="keyword-directive">import</span> de.matthiasmann.twl.Rect;
<span class="keyword-directive">import</span> de.matthiasmann.twl.ResizableFrame;
<span class="keyword-directive">import</span> de.matthiasmann.twl.ScrollPane;
<span class="keyword-directive">import</span> de.matthiasmann.twl.TextArea;
<span class="keyword-directive">import</span> de.matthiasmann.twl.Timer;
<span class="keyword-directive">import</span> de.matthiasmann.twl.ValueAdjusterInt;
<span class="keyword-directive">import</span> de.matthiasmann.twl.textarea.HTMLTextAreaModel;
<span class="keyword-directive">import</span> de.matthiasmann.twl.model.SimpleIntegerModel;
<span class="keyword-directive">import</span> de.matthiasmann.twl.renderer.lwjgl.LWJGLRenderer;
<span class="keyword-directive">import</span> de.matthiasmann.twl.textarea.StyleAttribute;
<span class="keyword-directive">import</span> de.matthiasmann.twl.textarea.StyleSheet;
<span class="keyword-directive">import</span> de.matthiasmann.twl.textarea.TextAreaModel;
<span class="keyword-directive">import</span> de.matthiasmann.twl.textarea.Value;
<span class="keyword-directive">import</span> de.matthiasmann.twl.theme.ThemeManager;
<span class="keyword-directive">import</span> de.matthiasmann.twl.utils.TextUtil;
<span class="keyword-directive">import</span> java.io.IOException;
<span class="keyword-directive">import</span> java.util.logging.Level;
<span class="keyword-directive">import</span> java.util.logging.Logger;
<span class="keyword-directive">import</span> org.lwjgl.opengl.Display;
<span class="keyword-directive">im</span><span class="keyword-directive">port</span> org.lwjgl.opengl.DisplayMode;
<span class="keyword-directive">import</span> org.lwjgl.opengl.GL11;
<span class="keyword-directive">import</span> test.SimpleTest;

<span class="comment">/**</span>
<span class="comment"> *</span>
<span class="comment"> * </span><span class="ST0">@author</span> <span class="comment">Matthias Mann</span>
 <span class="comment">*/</span>
<span class="keyword-directive">public</span> <span class="keyword-directive">class</span> TextAreaDemo <span class="keyword-directive">extends</span> DesktopArea {

    <span class="keyword-directive">public</span> <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> main(String[] args) {
        <span class="keyword-directive">try</span> {
            Display.setDisplayMode(<span class="keyword-directive">new</span> DisplayMode(800, 600));
            Display.create();
            Display.setTitle(<span class="character">&quot;</span><span class="character">TWL TextArea Demo</span><span class="character">&quot;</span>);
            Display.setVSyncEnabled(<span class="keyword-directive">true</span>);

            LWJGLRenderer renderer = <span class="keyword-directive">new</span> LWJGLRenderer();
            TextAreaDemo demo = <span class="keyword-directive">new</span> TextAreaDemo();
            GUI gui = <span class="keyword-directive">new</span> GUI(demo, renderer);

            ThemeManager theme = ThemeManager.createThemeManager(
                    TextAreaDemo.<span class="keyword-directive">class</span>.getResource(<span class="character">&quot;</span><span class="character">demo.xml</span><span class="character">&quot;</span>), renderer);
            gui.applyTheme(theme);

            <span class="keyword-directive">while</span>(!Display.isCloseRequested() &amp;&amp; !demo.quit) {
                GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);

                gui.update();

                <span class="comment">/**</span>
<span class="comment">                 * requires LWJGL 2.4 - for 2.3 just call Display.update()</span>
                 <span class="comment">*/</span>
                Display.update(<span class="keyword-directive">false</span>);
                GL11.glGetError();  <span class="comment">// force sync with multi threaded GL driver</span>
                Display.sync(60);   <span class="comment">// ensure 60Hz even without vsync</span>
                Display.processMessages();  <span class="comment">// now process inputs</span>
            }

            gui.destroy();
            theme.destroy();
        } <span class="keyword-directive">catch</span> (Exception ex) {
            SimpleTest.showErrMsg(ex);
        }
        Display.destroy();
    }

    <span class="keyword-directive">private</span> <span class="keyword-directive">final</span> FPSCounter fpsCounter;
    <span class="keyword-directive">private</span> <span class="keyword-directive">final</span> TextFrame textFrame;

    <span class="keyword-directive">public</span> <span class="keyword-directive">boolean</span> quit;

    <span class="keyword-directive">public</span> TextAreaDemo() {
        fpsCounter = <span class="keyword-directive">new</span> FPSCounter();
        add(fpsCounter);

        textFrame = <span class="keyword-directive">new</span> TextFrame();
        add(textFrame);

        textFrame.setSize(600, 500);
        textFrame.setPosition(40, 20);
    }

    @Override
    <span class="keyword-directive">pr</span><span class="keyword-directive">otected</span> <span class="keyword-directive">void</span> layout() {
        <span class="keyword-directive">super</span>.layout();

        <span class="comment">// fpsCounter is bottom right</span>
        fpsCounter.adjustSize();
        fpsCounter.setPosition(
                getInnerWidth() - fpsCounter.getWidth(),
                getInnerHeight() - fpsCounter.getHeight());
    }

    @Override
    <span class="keyword-directive">protected</span> <span class="keyword-directive">boolean</span> handleEvent(Event evt) {
        <span class="keyword-directive">if</span>(<span class="keyword-directive">super</span>.handleEvent(evt)) {
            <span class="keyword-directive">return</span> <span class="keyword-directive">true</span>;
        }
        <span class="keyword-directive">switch</span> (evt.getType()) {
            <span class="keyword-directive">case</span> KEY_PRESSED:
                <span class="keyword-directive">switch</span> (evt.getKeyCode()) {
                    <span class="keyword-directive">case</span> Event.KEY_ESCAPE:
                        quit = <span class="keyword-directive">true</span>;
                        <span class="keyword-directive">return</span> <span class="keyword-directive">true</span>;
                }
        }
        <span class="keyword-directive">return</span> <span class="keyword-directive">false</span>;
    }

    <span class="keyword-directive">static</span> <span class="keyword-directive">class</span> TextFrame <span class="keyword-directive">extends</span> ResizableFrame {
        <span class="keyword-directive">private</span> <span class="keyword-directive">final</span> HTMLTextAreaModel textAreaModel;
        <span class="keyword-directive">private</span> <span class="keyword-directive">final</span> TextArea textArea;
        <span class="keyword-directive">private</span> <span class="keyword-directive">final</span> ScrollPane scrollPane;
        <span class="keyword-directive">private</span> Timer timer;
        <span class="keyword-directive">priva</span><span class="keyword-directive">te</span> <span class="keyword-directive">int</span> size;
        <span class="keyword-directive">private</span> <span class="keyword-directive">int</span> dir;

        <span class="keyword-directive">private</span> <span class="keyword-directive">static</span> <span class="keyword-directive">final</span> <span class="keyword-directive">int</span> MIN_SIZE = 128;
        <span class="keyword-directive">private</span> <span class="keyword-directive">static</span> <span class="keyword-directive">final</span> <span class="keyword-directive">int</span> MAX_SIZE = 256;

        <span class="keyword-directive">public</span> TextFrame() {
            setTitle(<span class="character">&quot;</span><span class="character">Text</span><span class="character">&quot;</span>);

            <span class="keyword-directive">this</span>.textAreaModel = <span class="keyword-directive">new</span> HTMLTextAreaModel();
            <span class="keyword-directive">this</span>.textArea = <span class="keyword-directive">new</span> TextArea(textAreaModel);

            readFile(<span class="character">&quot;</span><span class="character">demo.html</span><span class="character">&quot;</span>);

            textArea.addCallback(<span class="keyword-directive">new</span> TextArea.Callback() {
                <span class="keyword-directive">public</span> <span class="keyword-directive">void</span> handleLinkClicked(String href) {
                    <span class="keyword-directive">if</span>(href.startsWith(<span class="character">&quot;</span><span class="character">javascript:</span><span class="character">&quot;</span>)) {
                        handleAction(href.substring(11));
                    } <span class="keyword-directive">else</span> <span class="keyword-directive">if</span>(href.startsWith(<span class="character">&quot;</span><span class="character">#</span><span class="character">&quot;</span>)) {
                        TextAreaModel.Element ankor = textAreaModel.getElementById(href.substring(1));
                        <span class="keyword-directive">i</span><span class="keyword-directive">f</span>(ankor != <span class="keyword-directive">null</span>) {
                            Rect rect = textArea.getElementRect(ankor);
                            <span class="keyword-directive">if</span>(rect != <span class="keyword-directive">null</span>) {
                                scrollPane.setScrollPositionY(rect.getY());
                            }
                        }
                    } <span class="keyword-directive">else</span> {
                        readFile(href);
                    }
                }
            });

            ValueAdjusterInt vai = <span class="keyword-directive">new</span> ValueAdjusterInt(<span class="keyword-directive">new</span> SimpleIntegerModel(0, 100, 50));
            vai.setTooltipContent(<span class="character">&quot;</span><span class="character">Select a nice value</span><span class="character">&quot;</span>);
            textArea.registerWidget(<span class="character">&quot;</span><span class="character">niceValueSlider</span><span class="character">&quot;</span>, vai);
            
            scrollPane = <span class="keyword-directive">new</span> ScrollPane(textArea);
            scrollPane.setFixed(ScrollPane.Fixed.HORIZONTAL);

            add(scrollPane);
        }

        @Override
        <span class="keyword-directive">protected</span> <span class="keyword-directive">void</span> afterAddToGUI(GUI gui) {
            <span class="keyword-directive">super</span>.afterAddToGUI(gui);
            timer = gui.createTimer();
            timer.setDelay(16);
            timer.setContinuous(<span class="keyword-directive">true</span>);
            timer.setCallback(<span class="keyword-directive">new</span> Runnable() {
                <span class="keyword-directive">public</span> <span class="keyword-directive">void</span> run() {
                    animate();
                }
            });
        }

        @Override
        <span class="keyword-directive">protected</span> <span class="keyword-directive">void</span> beforeRemoveFromGUI(GUI gui) {
            <span class="keyword-directive">super</span>.beforeRemoveFromGUI(gui);
            timer.stop();
            timer = <span class="keyword-directive">null</span>;
        }

        <span class="keyword-directive">void</span> readFile(String name) {
            <span class="keyword-directive">try</span> {
                textAreaModel.readHTMLFromURL(TextAreaDemo.<span class="keyword-directive">cla</span><span class="keyword-directive">ss</span>.getResource(name));

                StyleSheet styleSheet = <span class="keyword-directive">new</span> StyleSheet();
                <span class="keyword-directive">for</span>(String styleSheetLink : textAreaModel.getStyleSheetLinks()) {
                    <span class="keyword-directive">try</span> {
                        styleSheet.parse(TextAreaDemo.<span class="keyword-directive">class</span>.getResource(styleSheetLink));
                    } <span class="keyword-directive">catch</span>(IOException ex) {
                        Logger.getLogger(TextAreaDemo.<span class="keyword-directive">class</span>.getName()).log(Level.SEVERE,
                                <span class="character">&quot;</span><span class="character">Can&#39;t </span><span class="character">parse style sheet: </span><span class="character">&quot;</span> + styleSheetLink, ex);
                    }
                }
                textArea.setStyleClassResolver(styleSheet);
                
                setTitle(TextUtil.notNull(textAreaModel.getTitle()));

                size = MIN_SIZE;
                dir = -4;
            } <span class="keyword-directive">catch</span>(IOException ex) {
                Logger.getLogger(TextAreaDemo.<span class="keyword-directive">class</span>.getName()).log(Level.SEVERE, <span class="character">&quot;</span><span class="character">Can&#39;t read HTML: </span><span class="character">&quot;</span> + name, ex);
            }
        }

        <span class="keyword-directive">void</span> handleAction(String what) {
            <span class="keyword-directive">if</span>(<span class="character">&quot;</span><span class="character">zoomImage()</span><span class="character">&quot;</span>.equals(what)) {
                <span class="keyword-directive">i</span><span class="keyword-directive">f</span>(timer != <span class="keyword-directive">null</span> &amp;&amp; !timer.isRunning()) {
                    dir = -dir;
                    timer.start();
                }
            }
        }

        <span class="keyword-directive">void</span> animate() {
            size = Math.max(MIN_SIZE, Math.min(MAX_SIZE, size + dir));
            <span class="keyword-directive">if</span>(size == MIN_SIZE || size == MAX_SIZE) {
                timer.stop();
            }

            TextAreaModel.Element e = textAreaModel.getElementById(<span class="character">&quot;</span><span class="character">info</span><span class="character">&quot;</span>);
            <span class="keyword-directive">if</span>(e != <span class="keyword-directive">null</span>) {
                e.setStyle(e.getStyle().with(StyleAttribute.WIDTH, <span class="keyword-directive">new</span> Value(size, Value.Unit.PX)));
                textAreaModel.domModified();
            }
        }
    }
}
</pre>
<br/>The code listing was created using Netbeans' &quot;Print to HTML&quot; feature
</body>
</html>
